﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Framework.DataServicesEntities;
using Microsoft.WVB.Silverlight.Infrastructure;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Wpf.Events;

namespace Microsoft.WVB.UI
{
    public class ProgramModel : BaseController
    {
        private int _ratingId;
        private int _ratingNumberId;
        private int _durationId;
        private int _priceId;
        private int _iconId;

        private Program _program = null;

        public String Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Title));
            }
        }
        private string _Title = default(string);

        public String Category
        {
            get
            {
                return _Category;
            }
            set
            {
                _Category = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Category));
            }
        }
        private String _Category = default(string);

        public String Description
        {
            get
            {
                return _Description;
            }
            set
            {
                _Description = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Description));
            }
        }
        private String _Description = default(string);

        public int Duration
        {
            get
            {
                return _Duration;
            }
            set
            {
                _Duration = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Duration));
            }
        }
        private int _Duration = default(int);

        public Double Price
        {
            get
            {
                return _Price;
            }
            set
            {
                _Price = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Price));
            }
        }
        private Double _Price = default(Double);

        public Double PeopleRatings
        {
            get
            {
                return _PeopleRatings;
            }
            set
            {
                _PeopleRatings = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.PeopleRatings));
            }        
        }
        private Double _PeopleRatings = default(Double);

        public int NumberOfRatings
        {
            get
            {
                return _NumberOfRatings;
            }
            set
            {
                _NumberOfRatings = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.NumberOfRatings));
            }
        }
        private int _NumberOfRatings = default(int);

        public String Icon
        {
            get
            {
                return _Icon;
            }
            set
            {
                _Icon = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Icon));
            }
        }
        private String _Icon = null;

        public bool CanRate
        {
            get
            {
                return IoC.GetCreate<IUserManager>().IsAuthenticated;
            }
        }

        public bool Buffering
        {
            get
            {
                return _Buffering;
            }
            set
            {
                _Buffering = value;
                OnPropertyChanged(this.GetPropertySymbol(o => o.Buffering));
            }
        }
        private bool _Buffering = false;

        public ProgramModel()
        {
            initializeCachedId();
            IEventAggregator ag = IoC.GetCreate<IEventAggregator>();
            ag.GetEvent<ProgramChangedEvent>().Subscribe(this.SetProgram, ThreadOption.UIThread, true);
        }

        private void initializeCachedId()
        {
            EventHandler<ExecuteQueryCompletedEventArgs> idQueryHandler = null;

            DataFeedService feedSvc = IoC.GetCreate<DataFeedService>();
            string uri = String.Format("{0}/ProgramPropertyInfoCollection", feedSvc.RootService);

            if (idQueryHandler == null)
            {
                idQueryHandler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
                {
                    List<ProgramPropertyInfo> l = ((IEnumerable<ProgramPropertyInfo>)e.Result).ToList();

                    if (l != null)
                    {
                        var dId = l.FirstOrDefault((pp) => pp.Name == "Duration");
                        if (dId != null)
                            _durationId = dId.pvid;

                        var rId = l.FirstOrDefault((pp) => pp.Name == "Rating");
                        if (rId != null)
                            _ratingId = rId.pvid;

                        var nId = l.FirstOrDefault((pp) => pp.Name == "NumberOfRating");
                        if (nId != null)
                            _ratingNumberId = nId.pvid;

                        var pId = l.FirstOrDefault((pp) => pp.Name == "Price");
                        if (pId != null)
                            _priceId = pId.pvid;

                        var iconId = l.FirstOrDefault((pp) => pp.Name == "Icon");
                        if (iconId != null)
                            _iconId = iconId.pvid;
                    }

                    this.Buffering = false;
                    feedSvc.ExecuteQueryCompleted -= idQueryHandler;
                };
            }

            feedSvc.ExecuteQueryCompleted += idQueryHandler;
            feedSvc.ExecuteQueryAsync<ProgramPropertyInfo>(new Uri(uri, UriKind.Absolute), Guid.NewGuid());
            this.Buffering = true;
        }

        /// <summary>
        /// Used to specify to the component that the user has changed the program.
        /// </summary>
        /// <param name="currentProgramId"></param>
        //[MediatorEventHandler(Events.MessageTopics.ProgramChanged)]
        public virtual void SetProgram(Program program)
        {
            List<ProgramProperty> plist = program.Properties.ToList();
            List<Category> categoryList = program.Categories.ToList();

            this.Title = program.Name;
            this.Description = program.Description;

            if (plist != null)
            {
                var duration = plist.FirstOrDefault((pp) => pp.pvid == _durationId);
                if (duration != null)
                    this.Duration = int.Parse(duration.Value);

                var price = plist.FirstOrDefault((pp) => pp.pvid == _priceId);
                if (price != null)
                    this.Price = Double.Parse(price.Value);

                var peopleRatings = plist.FirstOrDefault((pp) => pp.pvid == _ratingId);
                if (peopleRatings != null)
                    this.PeopleRatings = Double.Parse(peopleRatings.Value);

                var nbOfRating = plist.FirstOrDefault((pp) => pp.pvid == _ratingNumberId);
                if (nbOfRating != null)
                    this.NumberOfRatings = int.Parse(nbOfRating.Value);

                var icon = plist.FirstOrDefault((pp) => pp.pvid == _iconId);
                if (icon != null)
                    this.Icon = icon.Value;

                this.Category = categoryList.FirstOrDefault().Name;
            }
        }

        /// <summary>
        /// When called, UpdateRating takes the current movie id, the userid and the rating passed as
        /// an argument to participate to the average rating of a give movie.
        /// If the user already rated the movie, the service will update the previous rating with 
        /// the rating argument and will recalculate the average with this new value and will
        /// return the result back. This method will then update the Rating property of ProgramModel
        /// with the average rating.
        /// </summary>
        /// <param name="rating"></param>
        public virtual void UpdateRating(Double rating)
        {
            EventHandler<ExecuteQueryCompletedEventArgs> updateHandler = null;
            DataFeedService feedSvc = IoC.GetCreate<DataFeedService>();
            IUser user = IoC.GetCreate<IUser>();
            string uri = String.Format("{0}/SetUserMovieRating?pid={1}&userId={2}&rating={3}", feedSvc.RootService, _program.programid, user.PPID, rating);

            updateHandler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
            {
                List<Double> newRates = (e.Result as IEnumerable<Double>).ToList();
                if (newRates != null)
                {
                    this.PeopleRatings = newRates.FirstOrDefault();
                }
                this.Buffering = false;
                feedSvc.ExecuteQueryCompleted -= updateHandler;
            };

            feedSvc.ExecuteQueryCompleted += updateHandler;
            feedSvc.ExecuteQueryAsync<Double>(new Uri(uri, UriKind.Absolute), Guid.NewGuid());
            this.Buffering = true;
        }
    }
}
